AddCSLuaFile("shared.lua")
AddCSLuaFile("cl_init.lua")

include("shared.lua")
include("sky_titans/shared/st_weapons.lua")
include("sky_titans/shared/st_ammo.lua")

function ENT:Initialize()
	self.Entity:PhysicsInit(SOLID_VPHYSICS)
	self.Entity:SetMoveType( MOVETYPE_VPHYSICS )
	self.Entity:SetTrigger( true )
	self.Entity:SetSolid(SOLID_VPHYSICS)
	self.Entity:SetUseType(SIMPLE_USE)

    local mass = 1
	local phys = self.Entity:GetPhysicsObject()
	if phys:IsValid() then 
	phys:Wake() 
    mass = phys:GetMass()
	end
    
    local weptable = st_weapons[self.Entity:GetModel()]
    self.name = weptable.name or ""
    self.ammotypes = weptable.ammotypes or {"AP"}
    self.ammotype = self.ammotypes[1]
    self.damage = weptable.damage or 0
    self.accuracy = weptable.accuracy or 0
    self.reload = weptable.reload or 5
    self.rate = weptable.rate or self.reload
    self.clip = weptable.clip or 1
    self.turn = weptable.turn or 0
    self.field = weptable.field or {180,0,0}
    self.recoil = weptable.recoil or {0,0}
    self.steam = weptable.steam or {0,0,0,0}
    self.effect = weptable.effect or {"st_fireeffect",1,"biggun4.wav",100,100,1}
    self.bones = weptable.bones
    self.barrels = table.Count(self.bones)-2
    
    self.pitch = 0
    self.addpitch = 0
    self.yaw = 0
    self.ammo = self.clip
    self.NextFire = CurTime()
    self.dofire = 0
    self.doreload = 0
    self.Core = NULL
    self.steamvent = 0
    
    self.maxhp = mass/2
    self.hp = self.maxhp
    self.repair = 1
    self.Entity:SetNetworkedFloat("repair", self.repair)
    self.Entity:SetNetworkedInt("fired",0)
    
    self.dps = self.damage*self.clip*self.barrels
    if(self.rate==self.reload) then self.dps = self.dps/self.reload else self.dps = self.dps/(self.reload + self.rate*self.clip) end
    self.cost = math.ceil( math.pow(self.dps*4,1.2) )
    self.Repay = 1
    Ent_InitCost( self.Entity )
    
    self.AmmoStr = "Ammo: "..table.concat(self.ammotypes,",")
    self.Inputs = Wire_CreateInputs(self, { "Fire", "Reload", self.AmmoStr ,"Add Pitch"})
end

function ENT:TriggerInput(iname, value)
	if (iname == "Fire") then
		self.dofire = value
	elseif (iname == "Reload") then
        self.doreload = value
    elseif(iname == self.AmmoStr) then
        local newammo = math.Clamp( math.ceil(value) , 1, table.Count(self.ammotypes))
        self.ammotype = self.ammotypes[newammo]
    elseif(iname == "Add Pitch" and self.addpitch==0) then
        self.addpitch = value
	end
end

function FireBullet( self, pos )
    local ent = ents.Create( st_ammo[self.ammotype].class )

    //local bulletPos = self.Entity:LocalToWorld(Vector(0,0,self.Entity:OBBCenter().z))
    local bulletPos = pos
    local bulletAng = self.Entity:LocalToWorldAngles(Angle(-self.pitch,-self.yaw,0))
    local bulletNorm = Vector(1,0,0) + VectorRand()*self.accuracy
        bulletNorm:Rotate( bulletAng )
    ent:SetPos( bulletPos )
    ent:SetAngles( bulletAng )
    ent.ammotype = self.ammotype
    ent.Gun = self.Entity
    ent.Owner = self.Owner
    ent.Core = self.Core
    ent.Norm = bulletNorm
    ent.damage = self.damage
    ent:Activate()
    ent:Spawn()
     
    local effectdata = EffectData()
    effectdata:SetOrigin( bulletPos )
    effectdata:SetNormal( bulletNorm:GetNormalized() )
    effectdata:SetScale( self.effect[2] )
    util.Effect( self.effect[1] , effectdata )
    sound.Play(self.effect[3],pos,self.effect[4],self.effect[5],self.effect[6])
end
    
function ENT:Think()
    
    local prevrepair = self.repair
    self.repair = math.min(self.repair+0.002,1)
    if(prevrepair==self.repair) then /*comment*/ else self.Entity:SetNetworkedFloat("repair", self.repair) end
    
    local phys = self.Entity:GetPhysicsObject()
    if( phys:IsValid() and self.Core:IsValid() ) then
    
        local b1 = Vector(self.bones[1].x,self.bones[1].y,self.bones[1].z)
        local b2 = Vector(self.bones[2].x,self.bones[2].y,self.bones[2].z)
            b2:Rotate(Angle(0,-self.yaw,0))
        
        //Handle aiming the weapon
        local pos = Vector(100,0,0)
        if( self.Core:IsValid() and self.Core.aimPos and self.Core.aimPos!=Vector(0,0,0)) then
            pos = self.Entity:WorldToLocal( self.Core.aimPos - (self.Entity:LocalToWorld(b2) - self.Entity:GetPos()) )
        end
        
        local rad2deg = 180 / math.pi
        local bearing = math.Clamp( rad2deg*-math.atan2(pos.y, pos.x) ,-self.field[1],self.field[1])
		local len = pos:Length()
        local elev = math.Clamp(rad2deg*math.asin(pos.z / len) +self.addpitch,self.field[3],self.field[2])
        
        local nextyaw = math.ApproachAngle(self.yaw,bearing,self.Core.pressure*(self.turn*(1+self.repair)/2)/5)
        local nextpitch = math.ApproachAngle(self.pitch,elev,self.Core.pressure*(self.turn*(1+self.repair)/2)/10)
        
        local addsteam = 0
        
        if(math.abs(self.yaw-nextyaw)>0.01) then
            self.yaw = nextyaw
            self.Entity:SetNetworkedFloat("yaw",self.yaw)
            addsteam = addsteam + self.steam[2]
        end
        if(math.abs(self.pitch-nextpitch)>0.01) then
            self.pitch = nextpitch
            self.Entity:SetNetworkedFloat("pitch",self.pitch)
            addsteam = addsteam + self.steam[2]
        end  
        
        self.steamvent = Lerp(0.99,self.steamvent,self.steam[1] + addsteam)
        
        //Handle firing the weapon
        if(self.NextFire < CurTime() and self.Owner:IsValid()) then
        
            if(self.dofire>0 and self.ammo>0) then

                for i=1,self.barrels do
                    local b3 = Vector(self.bones[2+i].x,self.bones[2+i].y,self.bones[2+i].z)
                        b3:Rotate(Angle(-self.pitch,-self.yaw,0))
                    FireBullet(self, self.Entity:LocalToWorld( b1+b2+b3 ) )
                end
                
                self.ammo = self.ammo-1
                if(self.recoil[1]>0) then 
                    self.Entity:SetNetworkedInt("fired",self.Entity:GetNetworkedInt("fired")+1) 
                end
                
                if(self.ammo<=0) then
                    self.ammo = self.clip
                    self.NextFire = CurTime()+ (self.reload + math.Rand(-self.reload/10,self.reload/10))*(1+(1-self.repair)*2)*(2-self.Core.pressure)
                    self.steamvent = self.steamvent + self.steam[3]
                else
                    self.NextFire = CurTime()+self.rate*(1+(1-self.repair))*(2-self.Core.pressure)
                    self.steamvent = self.steamvent + self.steam[4]
                end
            end
            
            if(self.doreload>0 and self.ammo<self.clip) then
                self.ammo = self.clip
                self.NextFire = CurTime()+self.reload*(1+(1-self.repair)*2)
            end
        end
        
        self.Entity:NextThink( CurTime() +0.01 )
    else
        self.Entity:NextThink( CurTime() + 1 )
    end
    
    return true
end

function ENT:OnRemove()
	RemoveRepay( self )
end

function ENT:OnRestore()
if WireLib then WireLib.Restored(self) end
end

function ENT:PreEntityCopy()
    if WireLib then
    local DupeInfo = WireLib.BuildDupeInfo(self)
        if DupeInfo then
            duplicator.StoreEntityModifier( self, "WireDupeInfo", DupeInfo )
        end
    end
end

function ENT:PostEntityPaste( Player, Ent, CreatedEntities )
    Ent.Owner = Player
    Ent_InitCost( self.Entity )
    if WireLib and (Ent.EntityMods) and (Ent.EntityMods.WireDupeInfo) then
        WireLib.ApplyDupeInfo(Player, Ent, Ent.EntityMods.WireDupeInfo, function(id) return CreatedEntities[id] end)
    end
end